/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ocr;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.*;

/**
 *
 * @author jenkin90
 */
public class RecognizedLetter {

    private String letter;
    private Integer area;
    private Double relativeArea;
    private Point centreOfMass;
    private BufferedImage image;
    private Double aInertia;
    private Double bInertia;
    private Double cInertia;
    private Integer minInertia;
    private Integer maxInertia;
    private Integer euler;
    private String letra;

    public RecognizedLetter(BufferedImage img) {
        this.image = img;
        this.area = area();
        this.centreOfMass = centreOfMass();
        this.aInertia = aInertia();
        this.bInertia = bInertia();
        this.cInertia = cInertia();
        this.minInertia = minInertia();
        this.maxInertia = maxInertia();
        this.relativeArea = relativeArea();
        this.euler = euler();
    }

    public RecognizedLetter(BufferedImage processedImage, String i) {
        this(processedImage);
        this.letra = i;

    }

    private Integer area() {
        Integer result = 0;
        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    result++;
                }
            }
        }
        return result;
    }

    private Point centreOfMass() {
        Integer xs = 0;
        Integer ys = 0;

        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    xs += i;
                    ys += j;
                }
            }
        }


        return new Point((int) xs / area, (int) ys / area);
    }

    private Integer minInertia() {
        Double res;

        Double b2 = bInertia * bInertia;
        Double ac = aInertia - cInertia;
        Double ac2 = Math.pow(ac, 2.0);

        Double sinAngle = bInertia / Math.sqrt(b2 + ac2);
        Double cosAngle = ac / Math.sqrt(b2 + ac2);

        res = 0.5 * (aInertia + cInertia) - 0.5 * ac * cosAngle - 0.5 * bInertia * sinAngle;
        return res.intValue();

    }

    private Integer maxInertia() {
        Double res;

        Double b2 = bInertia * bInertia;
        Double ac = aInertia - cInertia;
        Double ac2 = Math.pow(ac, 2.0);

        Double sinAngle = bInertia * (-1) / Math.sqrt(b2 + ac2);
        Double cosAngle = ac * (-1) / Math.sqrt(b2 + ac2);

        res = 0.5 * (aInertia + cInertia) - 0.5 * ac * cosAngle - 0.5 * bInertia * sinAngle;
        return res.intValue();
    }

    private Double aInertia() {
        Double result = 0.0;
        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    Double i2 = i - this.centreOfMass.getX();
                    //Double j2=j-this.centreOfMass().getY();
                    result += i2 * i2;
                }
            }
        }
        return result;
    }

    @Override
    public String toString() {
        String result = this.letra + "-->";
//        result += "Area: " + this.area + " ";
//        result += "Area relativa: " + this.relativeArea + " ";
//        result += "Centro de masas: (" + this.centreOfMass.getX() + "," + this.centreOfMass().getY() + ") ";
//        result += "Inercia min: " + this.minInertia + " ";
//        result += "Inercia max: " + this.maxInertia + " ";
//        result += "Euler: " + this.euler + " ";
//        result += "mu10: " + this.mupq(1, 0);

        result += "phi7=" + phi7() + "--";
        return result;
    }

    private Double bInertia() {
        Double result = 0.0;
        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    Double i2 = i - this.centreOfMass.getX();
                    Double j2 = j - this.centreOfMass().getY();
                    result += i2 * j2 * 2;
                }
            }
        }
        return result;
    }

    private Double cInertia() {
        Double result = 0.0;
        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    //Double i2=i-this.centreOfMass.getX();
                    Double j2 = j - this.centreOfMass().getY();
                    result += j2 * j2;
                }
            }
        }
        return result;
    }

    private Double relativeArea() {
        return (double) this.area / (this.image.getWidth() * this.image.getHeight());
    }

    private Integer euler() {
        Map<Integer, LabelsData> usedLabels = new HashMap<Integer, LabelsData>();
        List<List<Integer>> labels = Ocr.labelImage(this.image, Ocr.WHITE, usedLabels);

        Set<Integer> etiquetasABorrar = new HashSet<Integer>();
        for (Integer i : usedLabels.keySet()) {
            LabelsData temp = usedLabels.get(i);
            if (temp.getMinX().equals(0)) {
                etiquetasABorrar.add(i);
            }
            if (temp.getMinY().equals(0)) {
                etiquetasABorrar.add(i);
            }
            if (temp.getMaxX().equals(image.getWidth() - 1)) {
                etiquetasABorrar.add(i);
            }
            if (temp.getMaxY().equals(image.getHeight() - 1)) {
                etiquetasABorrar.add(i);
            }
        }
        for (Integer i : etiquetasABorrar) {
            usedLabels.remove(i);
        }


        return 1 - usedLabels.keySet().size();
    }

    public void setLetter(String letter) {
        this.letra = letter;
    }

    public Double getaInertia() {
        return aInertia;
    }

    public void setaInertia(Double aInertia) {
        this.aInertia = aInertia;
    }

    public Integer getArea() {
        return area;
    }

    public void setArea(Integer area) {
        this.area = area;
    }

    public Double getbInertia() {
        return bInertia;
    }

    public void setbInertia(Double bInertia) {
        this.bInertia = bInertia;
    }

    public Double getcInertia() {
        return cInertia;
    }

    public void setcInertia(Double cInertia) {
        this.cInertia = cInertia;
    }

    public Point getCentreOfMass() {
        return centreOfMass;
    }

    public void setCentreOfMass(Point centreOfMass) {
        this.centreOfMass = centreOfMass;
    }

    public Integer getEuler() {
        return euler;
    }

    public void setEuler(Integer euler) {
        this.euler = euler;
    }

    public BufferedImage getImage() {
        return image;
    }

    public void setImage(BufferedImage image) {
        this.image = image;
    }

    public String getLetra() {
        return letra;
    }

    public void setLetra(String letra) {
        this.letra = letra;
    }

    public Integer getMaxInertia() {
        return maxInertia;
    }

    public void setMaxInertia(Integer maxInertia) {
        this.maxInertia = maxInertia;
    }

    public Integer getMinInertia() {
        return minInertia;
    }

    public void setMinInertia(Integer minInertia) {
        this.minInertia = minInertia;
    }

    public Double getRelativeArea() {
        return relativeArea;
    }

    public void setRelativeArea(Double relativeArea) {
        this.relativeArea = relativeArea;
    }

    private Double mupq(Integer p, Integer q) {
        Double result = 0.0;
        for (int i = 0; i < this.image.getWidth(); i++) {
            for (int j = 0; j < this.image.getHeight(); j++) {
                if (this.image.getRGB(i, j) == Ocr.BLACK) {
                    Double temp1 = Math.pow(i - this.getCentreOfMass().getX(), p);
                    Double temp2 = Math.pow(j - this.getCentreOfMass().getY(), q);
                    Double temp3 = temp1 * temp2;
                    result += temp3;
                }
            }
        }
        return result;
    }

    private Double ñupq(Integer p, Integer q) {
        Double p2 = p.doubleValue();
        Double q2 = q.doubleValue();
        Double alpha = (p2 + q2) / 2.0 + 1.0;

        Double numerador = mupq(p, q);
        Double denominador = Math.pow(mupq(0, 0), alpha);
        return numerador / denominador;

    }

    public double phi1() {
        return ñupq(2, 0) + ñupq(0, 2);
    }

    public double phi2() {
        Double temp1 = Math.pow(ñupq(2, 0) - ñupq(0, 2), 2);
        Double temp2 = 4 * Math.pow(ñupq(1, 1), 2);
        return temp1 + temp2;
    }

    public double phi3() {
        Double temp1 = Math.pow(ñupq(3, 0) - ñupq(1, 2), 2);
        Double temp2 = Math.pow(3 * ñupq(2, 1) - ñupq(0, 3), 2);
        return temp1 + temp2;
    }

    public double phi4() {
        Double temp1 = Math.pow(ñupq(3, 0) - ñupq(1, 2), 2);
        Double temp2 = Math.pow(ñupq(2, 1) - ñupq(0, 3), 2);
        return temp1 + temp2;
    }

    public double phi5() {
        Double ñu30 = ñupq(3, 0);
        Double ñu12 = ñupq(1, 2);
        Double ñu21 = ñupq(2, 1);
        Double ñu03 = ñupq(0, 3);

        Double temp1 = (ñu30 - 3 * ñu12) * (ñu30 + ñu12);
        Double temp2 = Math.pow(ñu30 + ñu12, 2);
        Double temp3 = Math.pow(ñu21 + ñu03, 2) * 3;
        Double temp4 = temp2 - temp3;
        Double temp5 = temp1 * temp4;

        Double temp6 = (3 * ñu21 - ñu03) * (ñu21 + ñu03);
        Double temp7 = Math.pow(ñu30 + ñu12, 2) * 3;
        Double temp8 = Math.pow(ñu21 + ñu03, 2);
        Double temp9 = temp7 - temp8;
        Double temp10 = temp6 * temp9;

        return temp5 + temp10;



    }

    public double phi6() {
        Double ñu20 = ñupq(2, 0);
        Double ñu02 = ñupq(0, 2);
        Double ñu30 = ñupq(3, 0);
        Double ñu12 = ñupq(1, 2);
        Double ñu21 = ñupq(2, 1);
        Double ñu11 = ñupq(1, 1);
        Double ñu03 = ñupq(0, 3);

        Double temp1 = (ñu20 - ñu02) * (ñu30 + ñu12);
        Double temp2 = Math.pow(ñu30 + ñu12, 2);
        Double temp3 = Math.pow(ñu21 + ñu03, 2);
        Double temp4 = temp1 * (temp2 - temp3);
        Double temp5 = 4 * ñu11 * (ñu30 + ñu12) * (ñu21 + ñu03);


        return temp4 + temp5;
    }
    
    public double phi7() {

        Double ñu30 = ñupq(3, 0);
        Double ñu12 = ñupq(1, 2);
        Double ñu21 = ñupq(2, 1);
        Double ñu03 = ñupq(0, 3);

        Double temp1=(3*ñu21-ñu03)*(ñu30+ñu12);
        Double temp2=Math.pow(ñu30+ñu12,2);
        Double temp3=Math.pow(ñu21+ñu03,2)*3;
        Double temp4=temp1*(temp2-temp3);
        
        Double temp5=(ñu30-3*ñu12)*(ñu21+ñu03);
        Double temp6=Math.pow(ñu30+ñu12,2)*3;
        Double temp7=Math.pow(ñu21+ñu03,2);
        Double temp8=temp5*(temp6-temp7);
        
        


        return temp4 - temp8;
    }
}
